const PENDING = "PENDING";
const FULFILLED = "FULFILLED";
const REJECTED = "REJECTED";

class MyPromise {
  constructor(executor) {
    executor(this.resolve, this.reject)
  }
  state = PENDING;
  promiseResult = undefined;
  onFullfilledCB = [];
  onRejectedCB = [];

  resolve(res) {
    if (this.state !== PENDING) return;
    this.state = FULFILLED;
    this.promiseResult = res;
    while(this.onFullfilledCB.length) {
      this.onFullfilledCB.shift()();
    }
  }

  reject(res) {
    if (this.state !== PENDING) return;
    this.state = REJECTED;
    this.promiseResult = res;
    while(this.onRejectedCB.length) {
      this.onRejectedCB.shift()();
    }
  }

  then(onFulfilled, onRejected) {
    if (typeof onFulfilled !== "function") {
      onFulfilled = val => val;
    }
    if (typeof onRejected !== "function") {
      onRejected = val => val;
    }
    return new Promise((nextResolve, nextRejected) => {
      const returnPromise = (func) => {
        try {
          const res = func(this.promiseResult);
          if (res instanceof MyPromise) {
            res.then(nextResolve, nextRejected)
          } else {
            nextResolve(res)
          }
        } catch(err) {
          onRejected(err);
        }
      }
      if (this.state == FULFILLED) {
        returnPromise(onFulfilled)
      } else if (this.state == REJECTED) {
        returnPromise(onRejected)
      } else {
        this.onFulfilledCallback.push(() => returnPromise(onFulfilled));
        this.onRejectedCallback.push(() => returnPromise(onRejected));
      }
    })
    // if (this.state === FULFILLED) {
    //   onFulfilled(this.promiseResult)
    // } else if (this.state === REJECTED) {
    //   onRejected(this.promiseResult)
    // } else if (this.state === PENDING) {
    //   this.onFullfilledCB.push(onFulfilled)
    //   this.onRejectedCB.push(onRejected)
    // }
  }

  static all(promises) {
    return new MyPromise((resolve, reject) => {
      let count = 0;
      let arr = []
      for (var i = 0; i < promises.length; i++) {
        promises[i].then(res => {
          count++;
          arr[i] = res;
          if (count == promises.length) {
            resolve(arr)
          }
        }, r => reject(r))
      }
    })
  }

  static race(promises) {
    return new Promise((resolve, reject) => {
      for (var i = 0; i < promises.length;i++) {
        promises[i].then(r => {
          resolve(r)
        }, r => reject(r))
      }
    })
  }
  
}

